
/**
 * apply
 * 描述：Function 实例的 apply() 方法会以给定的 this 值和作为数组（或类数组对象）提供的 arguments 调用该函数。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
 */

/**
 * apply语法
 * apply(thisArg)
 * apply(thisArg, argsArray) argsArray类数组对象
 
 */


const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);

console.log(max);
// Expected output: 7

const min = Math.min.apply(null, numbers);
console.log(min);
// Expected output: 2


// 手写apply实现
Function.prototype.myapply = function (target, args) {
  target = typeof target === 'object' ? target : window;
  if (['string', 'number', 'boolean'].includes(typeof args)) {
    throw new Error('arg类型错误')
  }
  let funcArgs = Object.prototype.toString.call(args) === '[Object Array]' ? args : [];

  let uniquefun = Symbol('fun');
  target[uniquefun] = this;

  //执行函数 (类型obj.getName())
  let result = target[uniquefun](funcArgs)

  delete target[uniquefun]

  return result;

}

function test(args) {
  let arr = Array.prototype.splice.call(args, ',');
  console.log('arr', arr);


}
test.myapply({}, [2, 3, 4,])






/**
 * call
 * 描述：Function 实例的 call() 方法会以给定的 this 值和逐个提供的参数调用该函数。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call
 */


/**
 * call语法
 * 
 * call(thisArg)
 * call(thisArg, arg1)
 * call(thisArg, arg1, arg2)
 * call(thisArg, arg1, arg2, …)
 */


function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = "food";
}

console.log(new Food("cheese", 5).name);
// Expected output: "cheese"



Function.prototype.mycall = function (target, ...args) {
  target = typeof target === 'object' ? target : window;

  let uniquefun = Symbol('fun');
  target[uniquefun] = this;
  let result = target[uniquefun](...args)

  delete target[uniquefun]
  return result
}



/**
 * bind
 * 
 * 描述：Function 实例的 bind() 方法创建一个新函数，当调用该新函数时，它会调用原始函数并将其 this 关键字设置为给定的值，同时，还可以传入一系列指定的参数，这些参数会插入到调用新函数时传入的参数的前面。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
 */

/**
 * bind语法
 * 
 * bind(thisArg)
 * bind(thisArg, arg1)
 * bind(thisArg, arg1, arg2)
 * bind(thisArg, arg1, arg2, ... argN) 
 * */


const module = {
  x: 42,
  getX: function () {
    return this.x;
  },
};

const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// Expected output: undefined

const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// Expected output: 42


Function.prototype.mybind = function (target, ...args) {
  let func = this;

  return function (...newArgs) {
    // 合并预先设置的参数和新的调用参数
    const finalArgs = args.concat(newArgs);
    func.apply(target, finalArgs)
  }
}